package com.anlogic.sdk.bootimage.internal.ui.composite;

import com.anlogic.sdk.bootimage.internal.ui.AutoCompleteProvider;
import com.anlogic.sdk.bootimage.internal.ui.common.BootgenComboViewer;
import com.anlogic.sdk.bootimage.internal.ui.common.BootgenStringRadioField;
import com.anlogic.sdk.bootimage.internal.ui.common.BootgenTextField;
import com.anlogic.sdk.bootimage.internal.ui.common.IFileBrowseInput;
import com.anlogic.sdk.bootimage.internal.ui.common.IFileBrowseInputInitListener;
import com.anlogic.sdk.bootimage.internal.ui.common.IModifyListener;
import com.anlogic.sdk.bootimage.internal.ui.common.IUIValidator;
import com.anlogic.sdk.bootimage.model.BifReader;
import com.anlogic.sdk.bootimage.model.BootGenModel;
import com.anlogic.sdk.utils.LogUtils;
import com.anlogic.sdk.utils.StringUtils;
import com.anlogic.sdk.utils.UIUtils;
import com.anlogic.sdk.utils.options.ChipType;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.logging.log4j.Logger;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;

public class BootGenMainComposite extends AbsBootgenComposite {
	private static Logger logger = LogUtils.getLogger(BootGenMainComposite.class);

	private static final String OPT_IMPORT_FROM_EXISTING_BIF_FILE = "Import from existing BIF file";

	private static final String OPT_CREATE_NEW_BIF_FILE = "Create new BIF file";

	private BasicSectionComposite basicComposite;

	private SecurityTabComposite secuirtyComposite;

	protected PartitionTableComposite partitonTableComposite;

	protected BootgenStringRadioField bifModelTypeField;

	protected BootgenComboViewer<ChipType> chipTypeComboViewer;

	protected BootgenTextField importBifField;

	protected List<AbsBootgenComposite> uiComponents = new ArrayList<>();

	protected Composite tabFolderContainer;

	public BootGenMainComposite(Composite parent, BootGenModel model) {
		super(parent, 0, model, (AutoCompleteProvider.IAutoCompeletHelper) null);
		createUI(this);
	}

	private void createUI(Composite container) {
		GridDataFactory.fillDefaults().grab(true, false).hint(250, -1).applyTo((Control) container);
		GridLayoutFactory.fillDefaults().numColumns(3).margins(5, 5).applyTo(container);
		Composite chipTypeComposite = new Composite(container, 0);
		GridDataFactory.swtDefaults().span(3, 1).applyTo((Control) chipTypeComposite);
		GridLayoutFactory.fillDefaults().numColumns(2).applyTo(chipTypeComposite);
		this.chipTypeComboViewer = new BootgenComboViewer<>(this);
		this.chipTypeComboViewer.createField(chipTypeComposite, "ChipType: ", (Object[]) ChipType.getValues().toArray(new ChipType[0]));
		GridDataFactory.swtDefaults().applyTo((Control) this.chipTypeComboViewer.getControl());
		this.bifModelTypeField = new BootgenStringRadioField(this);
		this.bifModelTypeField.createField(container, null,
				(Object[]) new String[] { OPT_CREATE_NEW_BIF_FILE, OPT_IMPORT_FROM_EXISTING_BIF_FILE });
		this.bifModelTypeField.setDefaultGridData(3);
		this.importBifField = new BootgenTextField(this);
		this.importBifField.createOpenBrowseField(container, "Import BIF file path", "bootgen_files_selection",
				BIF_EXTENSIONS);
		this.importBifField.setDefaultGridData(1);
		this.tabFolderContainer = new Composite(this, 0);
		GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo((Control) this.tabFolderContainer);
		GridLayoutFactory.fillDefaults().applyTo(this.tabFolderContainer);
		TabFolder tabFolder = new TabFolder(this.tabFolderContainer, 0);
		GridDataFactory.fillDefaults().grab(true, true).applyTo((Control) tabFolder);
		TabItem basicTabItem = new TabItem(tabFolder, 0);
		this.basicComposite = new BasicSectionComposite((Composite) tabFolder, this.model, getAutoCompleteHelper());
		GridDataFactory.fillDefaults().grab(true, false).applyTo((Control) this.basicComposite);
		basicTabItem.setText("Basic");
		basicTabItem.setControl((Control) this.basicComposite);
		this.uiComponents.add(this.basicComposite);
		TabItem securityTabItem = new TabItem(tabFolder, 0);
		this.secuirtyComposite = new SecurityTabComposite((Composite) tabFolder, this.model, getAutoCompleteHelper());
		securityTabItem.setText("Security");
		securityTabItem.setControl((Control) this.secuirtyComposite);
		this.uiComponents.add(this.secuirtyComposite);
		tabFolder.pack();
		createAdditionalControls(container);
		
		if (model.isNew()) {
			if (!model.getBifFile().isEmpty()) {
				this.loadAndRefreshModel(model.getBifFile(), true);
				this.validateUI();
			}
		} else {
			if (!model.getImportBifFile().isEmpty()) {
				this.loadAndRefreshModel(model.getImportBifFile(), false);
				this.validateUI();
			}
		}
	}

	protected void createAdditionalControls(Composite container) {
		this.partitonTableComposite = new PartitionTableComposite(container, this.model);
		int vHint = UIUtils.convertHeightInCharsToPixels((Control) this.partitonTableComposite, 20);
		GridDataFactory.fillDefaults().grab(true, true).hint(-1, vHint).span(3, 1)
				.applyTo((Control) this.partitonTableComposite);
		this.uiComponents.add(this.partitonTableComposite);
		this.secuirtyComposite.setPartitionTable(partitonTableComposite);
	}

	public void addListeners() {
		addFieldListeners();
		addCompositeListeners();
	}

	public void setUiValidator(IUIValidator uiValidator) {
		super.setUiValidator(uiValidator);
		for (AbsBootgenComposite uiComponent : this.uiComponents)
			uiComponent.setUiValidator(uiValidator);
	}

	protected void addFieldListeners() {
		this.chipTypeComboViewer.setModifyListener(new IModifyListener<ChipType>() {
			public void valueChanged(ChipType chipType) {
				BootGenMainComposite.this.model.setChipType(chipType);
				BootGenMainComposite.this.resetForArchitecture();
				BootGenMainComposite.this.refreshCompleteUI();
				BootGenMainComposite.this.markEditedAndValidate();
			}
		});
		this.bifModelTypeField.setModifyListener(new IModifyListener<String>() {
			public void valueChanged(String newValue) {
				boolean isNew = newValue.equals(OPT_CREATE_NEW_BIF_FILE);
				BootGenMainComposite.this.model.setNew(isNew);
				BootGenMainComposite.this.refreshCompleteUI();
				BootGenMainComposite.this.markEditedAndValidate();
			}
		});
		this.importBifField.setModifyListener(new IModifyListener<String>() {
			public void valueChanged(String importBifPath) {
				BootGenMainComposite.this.loadAndRefreshModel(importBifPath, false);
				BootGenMainComposite.this.markEditedAndValidate();
			}
		});
		this.importBifField.setBrowseInputInitListener(new IFileBrowseInputInitListener() {
			public void initialize(IFileBrowseInput fileBrowseInput) {
				BasicSectionComposite.updateBifBrowseInput(BootGenMainComposite.this.importBifField.getSelection(),
						fileBrowseInput);
			}
		});
		this.basicComposite.setOutBifPathLisener(new IModifyListener<String>() {
			public void valueChanged(String newValue) {
				BootGenMainComposite.this.refreshAllContentProposals();
			}
		});
	}

	private void addCompositeListeners() {
		for (AbsBootgenComposite uiComponent : this.uiComponents)
			uiComponent.addListeners();
	}

	private void refreshAllContentProposals() {
		refreshContentProposals();
		for (AbsBootgenComposite uiComponent : this.uiComponents)
			uiComponent.refreshContentProposals();
	}

	private void loadAndRefreshModel(String importBifPath, boolean isNew) {
		BootGenModel newImportedModel = new BootGenModel();
		newImportedModel.setBifFile(importBifPath);
		newImportedModel.setImportBifFile(importBifPath);
		newImportedModel.setNew(isNew);
		if (StringUtils.isNotEmpty(importBifPath) && (new File(importBifPath)).isFile()) {
			try {
				logger.info("Read bif file {}", importBifPath);
				BifReader.newInstance(importBifPath).readBif(newImportedModel);
			} catch (IOException e) {
				logger.error("Failed to read bif file {}", importBifPath);
			}
			logger.info("Read bif file {} success", importBifPath);
		}

		this.model = newImportedModel;
		updateAndRefreshModels();
	}

	private void updateAndRefreshModels() {
		updateModel(this.model);
		for (AbsBootgenComposite uiComponent : this.uiComponents)
			uiComponent.updateModel(this.model);
	}

	public void refreshCompleteUI() {
		refreshUI();
		for (AbsBootgenComposite uiComponent : this.uiComponents)
			uiComponent.refreshUI();
	}

	public void refreshUI() {
		UIUtils.excludeWidget((Control) this.importBifField.getControl(), this.model.isNew());
		layout(true);
		super.refreshUI();
	}

	public void loadUI() {
		this.chipTypeComboViewer.setSelection(this.model.getChipType());
		this.model.setChipType(this.chipTypeComboViewer.getSelection());
		String bifModelSelection = this.model.isNew() ? OPT_CREATE_NEW_BIF_FILE : OPT_IMPORT_FROM_EXISTING_BIF_FILE;
		this.bifModelTypeField.setSelection(bifModelSelection);
		if (!this.importBifField.getSelection().equals(this.model.getImportBifFile()))
			this.importBifField.setSelection(this.model.getImportBifFile());
	}

	public BootGenModel getModel() {
		return this.model;
	}

	protected void resetForArchitecture() {
		this.model.resetForArchitecture();
	}
}
